package com.wisedu.mobile.auth.service.impl.v1.ldap;

import com.wisedu.mobile.auth.service.impl.v1.db.SysUserServiceImpl;
import com.wisedu.mobile.common.BaseException;
import com.wisedu.mobile.common.constant.UserConstants;
import com.wisedu.mobile.common.domain.LoginUser;
import com.wisedu.mobile.common.domain.SysMenu;
import com.wisedu.mobile.common.domain.SysRole;
import com.wisedu.mobile.common.domain.SysUser;
import com.wisedu.mobile.common.service.ISysUserService;
import com.wisedu.mobile.common.utils.MessageUtils;
import org.nutz.json.Json;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 用户验证处理
 *
 * @author hj
 */
@Service
@ConditionalOnProperty(prefix = "auth", name = "way", havingValue = "ldap")
public class UserDetailsServiceImpl implements UserDetailsService {
    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

    @Autowired
    private SysUserServiceImpl userService;

    @Autowired
    private LdapTemplate ldapTemplate;

    @Value("ldap.searchFilter")
    private String searchFilter;

    @Value("ldap.searchBase")
    private String searchBase;

    @Value("ldap.uid")
    private String searchUid;

    @Value("ldap.cn")
    private String searchCn;


    @Override
    public UserDetails loadUserByUsername(String loginname) throws UsernameNotFoundException {
        SysUser user = null;
        try {
            user = getUserById(loginname);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (user == null) {
                log.info("登录用户：" + loginname + " 不存在");
                throw new UsernameNotFoundException(MessageUtils.message("user.notfound", loginname));
            } else {
                SysUser dbuser = userService.selectUserByLoginName(loginname);
                if (dbuser == null) {
                    userService.insert(user);
                }else{
                    user = dbuser;
                }
            }
            log.info("user: " + user);
        }

        userService.selectRoleByUser(user);
        Set<String> perms = new HashSet<String>();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            perms.add("*:*:*");
        } else {
            for (SysRole role : user.getRoles()) {
                for (SysMenu menu : role.getMenus()) {
                    perms.add(menu.getUrl() + ":" + menu.getHttpMethod());
                }
            }
        }
        return new LoginUser(user, perms);
    }

    /*
    * 身份认证
    */
    public boolean authenticate(String userName, String password) {
        return this.ldapTemplate.authenticate(
                this.searchBase, String.format(this.searchFilter, userName), password);
    }

    public SysUser getUserById(String uid) {
        return ldapTemplate.searchForObject(this.searchBase,
                String.format(this.searchFilter, uid),
                new ContextMapper<SysUser>() {
                    @Override
                    public SysUser mapFromContext(Object ctx) throws javax.naming.NamingException {
                        SysUser sysUser = new SysUser();
                        DirContextOperations context = (DirContextOperations) ctx;
                        String userId = context.getStringAttribute(searchUid);
                        log.info("uid: " + userId);
                        sysUser.setId(userId);
                        sysUser.setLoginName(userId);
                        String cn = context.getStringAttribute(searchCn);
                        log.info("cn: " + cn);
                        sysUser.setUserName(cn);
                        return sysUser;
                    }
                });

    }
}
